home *** CD-ROM | disk | FTP | other *** search
/ Aminet 45 / Aminet 45 (2001)(GTI - Schatztruhe)[!][Oct 2001].iso / Aminet / dev / gui / FoxGuiSource.lha / FoxLibSource / Images.c < prev    next >
C/C++ Source or Header  |  2001-07-07  |  20KB  |  731 lines

  1. /* FoxGUI - The fast, flexible, free Amiga GUI system
  2.     Copyright (C) 2001 Simon Fox (Foxysoft)
  3.  
  4. This library is free software; you can redistribute it and/ormodify it under the terms of the GNU Lesser General PublicLicense as published by the Free Software Foundation; eitherversion 2.1 of the License, or (at your option) any later version.This library is distributed in the hope that it will be useful,but WITHOUT ANY WARRANTY; without even the implied warranty ofMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNULesser General Public License for more details.You should have received a copy of the GNU Lesser General PublicLicense along with this library; if not, write to the Free SoftwareFoundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
  5. Foxysoft: www.foxysoft.co.uk      Email:simon@foxysoft.co.uk                */
  6.  
  7.  
  8. /******************************************************************************
  9.  * Shared library code.  Cannot call functions which use exit() such as:
  10.  * printf(), fprintf()
  11.  *
  12.  * Otherwise:
  13.  * The linker returns "__XCEXIT undefined" and the program will fail.
  14.  * This is because you must not exit() a library!
  15.  *
  16.  * Also:
  17.  * proto/exec.h must be included instead of clib/exec_protos.h and
  18.  * __USE_SYSBASE must be defined.
  19.  *
  20.  * Otherwise:
  21.  * The linker returns "Absolute reference to symbol _SysBase" and the
  22.  * library crashes.  Presumably the same is true for the other protos.
  23.  ******************************************************************************/
  24.  
  25. #define __USE_SYSBASE
  26.  
  27. #define FOXGUI_IMAGES    // Used to stop iffp/ilbm.h from redefining GfxBase & IntuitionBase.
  28.  
  29. #include <proto/mathieeedoubbas.h>
  30. #include <stdlib.h>
  31. #include <math.h>
  32.  
  33. #include <libraries/dos.h>
  34. #include <libraries/iffparse.h>
  35. #include <proto/graphics.h>
  36. #include <proto/intuition.h>
  37. #include <proto/exec.h>
  38. #include <proto/dos.h>
  39. #include <proto/graphics.h>
  40. #include <graphics/gfx.h>
  41. #include <graphics/scale.h>
  42.  
  43. #define USE_BUILTIN_MATH 1  // to use built-in min() and max() in string.h
  44. #include <string.h>
  45.  
  46. #include <graphics/display.h>
  47. #include <intuition/intuition.h>
  48.  
  49. #define NO_PROTOS
  50. #define NO_SAS_PRAGMAS
  51.  
  52. #include <iffp/ilbm.h>
  53. #include <iffp/packer.h>
  54.  
  55. #include "/foxinclude/foxgui.h"
  56. #include "FoxGuiTools.h"
  57.  
  58. #define MaxSrcPlanes (25)
  59.  
  60. static void freeBitMap(struct BitMap *bm)
  61.    {
  62.    short j;
  63.  
  64.     if (bm)
  65.         {
  66.         for (j = 0; j < bm->Depth; j++)
  67.             if (bm->Planes[j])
  68.                 FreeRaster(bm->Planes[j], bm->BytesPerRow << 3, bm->Rows);
  69.         FreeMem(bm, sizeof(struct BitMap));
  70.         }
  71.     }
  72.  
  73. static struct BitMap *getBitMap(int wide, int high, int deep, short clear)
  74.     {
  75.     register short i;
  76.     struct BitMap *bitmap;
  77.  
  78.     if (!(bitmap = (struct BitMap *) AllocMem(sizeof(struct BitMap), MEMF_PUBLIC|MEMF_CLEAR)))
  79.         return NULL;
  80.  
  81.     InitBitMap(bitmap, deep, wide, high);
  82.     for (i = 0; i < deep; i++)
  83.         {
  84.         if (!(bitmap->Planes[i] = (PLANEPTR)AllocRaster(wide, high)))
  85.             {
  86.             freeBitMap(bitmap);
  87.             return NULL;
  88.             }
  89.         if (clear)
  90.             BltClear(bitmap->Planes[i], RASSIZE(wide, high), 0);
  91.         }
  92.     return bitmap;
  93.     }
  94.  
  95. static BOOL unpackrow(BYTE **pSource, BYTE **pDest, WORD srcBytes0, WORD dstBytes0)
  96.     {
  97.     register BYTE *source = *pSource;
  98.     register BYTE *dest = *pDest;
  99.     register WORD n;
  100.     register WORD srcBytes = srcBytes0, dstBytes = dstBytes0;
  101.     register BYTE c;
  102.     BOOL error = TRUE;  // assume error until we make it through the loop
  103.     WORD minus128 = -128;  // get the compiler to generate a CMP.W
  104.  
  105.     while (dstBytes > 0)
  106.         {
  107.         if (--srcBytes < 0)
  108.             goto errorexit;
  109.         n = *source++;
  110.         if (n >= 0)
  111.             {
  112.             ++n;
  113.             if ((srcBytes -= n) < 0)
  114.                 goto errorexit;
  115.             if ((dstBytes -= n) < 0)
  116.                 goto errorexit;
  117.             do {
  118.                 *dest++ = *source++;
  119.                 } while (--n > 0);
  120.             }
  121.         else if (n != minus128)
  122.             {
  123.             n = 1 - n;
  124.             if (--srcBytes < 0)
  125.                 goto errorexit;
  126.             if ((dstBytes -= n) < 0)
  127.                 goto errorexit;
  128.             c = *source++;
  129.             do {
  130.                 *dest++ = c;
  131.                 } while (--n > 0);
  132.             }
  133.         }
  134.     error = FALSE;  // success!
  135.  
  136. errorexit:
  137.     *pSource = source;
  138.     *pDest = dest;
  139.     return error;
  140.     }
  141.  
  142.  
  143. static int loadbody2(struct IFFHandle *iff, struct BitMap *bitmap, BYTE *mask, BitMapHeader *bmhd,
  144.         BYTE *buffer, ULONG bufsize)
  145.     {
  146.     register int iPlane, iRow, nEmpty;
  147.     register WORD nFilled;
  148.     WORD srcRowBytes = RowBytes(bmhd->w), destRowBytes = bitmap->BytesPerRow,
  149.         destWidthBytes,   // used for width check
  150.         compression = bmhd->compression;
  151.     LONG bufRowBytes = MaxPackedSize(srcRowBytes);
  152.     int nRows = bmhd->h;
  153.     struct ContextNode *cn = CurrentChunk(iff);
  154.     UBYTE srcPlaneCnt = bmhd->nPlanes;
  155.     BYTE *buf, *nullDest, *nullBuf, **pDest, *planes[MaxSrcPlanes];   // array of ptrs to planes & mask
  156.  
  157.     if (compression > cmpByteRun1)
  158.         return 1;
  159.  
  160.     if (((struct Library *)GfxBase)->lib_Version >= 39)
  161.         destWidthBytes = RowBytes(GetBitMapAttr(bitmap, BMA_WIDTH));
  162.     else
  163.         destWidthBytes = destRowBytes;
  164.  
  165.     if (srcRowBytes > destWidthBytes || bufsize < (bufRowBytes<<1) || srcPlaneCnt > MaxSrcPlanes)
  166.         return 1;
  167.     if (nRows > bitmap->Rows)
  168.         nRows = bitmap->Rows;
  169.  
  170.     // Initialize array "planes" with bitmap ptrs; NULL in empty slots.
  171.     for (iPlane = 0; iPlane < bitmap->Depth; iPlane++)
  172.         planes[iPlane] = (BYTE *)bitmap->Planes[iPlane];
  173.  
  174.     while (iPlane < MaxSrcPlanes)
  175.         planes[iPlane++] = NULL;
  176.  
  177.     // copy any mask plane ptr into corresponding "planes" slot.
  178.     if (bmhd->masking == mskHasMask)
  179.         planes[srcPlaneCnt++] = mask ? mask : NULL;
  180.  
  181.     // Set up a sink for dummy destination of rows from unwanted planes
  182.     nullDest = buffer;
  183.     buffer += srcRowBytes;
  184.     bufsize -= srcRowBytes;
  185.  
  186.     // Read the BODY contents into bitmap.
  187.     // De-interleave planes, decompress rows.
  188.     // MODIFIES: Last iteration modifies bufsize.
  189.  
  190.     buf = buffer + bufsize;  // buffer is currently empty
  191.     for (iRow = nRows; iRow > 0; iRow--)
  192.         {
  193.         for (iPlane = 0; iPlane < srcPlaneCnt; iPlane++)
  194.             {
  195.             pDest = &planes[iPlane];
  196.             if (!(*pDest))    // establish sink for any unwanted plane
  197.                 {
  198.                 nullBuf = nullDest;
  199.                 pDest = &nullBuf;
  200.                 }
  201.             // read in at least enough bytes to uncompress next row
  202.             nEmpty = buf - buffer;       // size of empty part of buffer
  203.             nFilled = bufsize - nEmpty;  // this part has data
  204.             if (nFilled < bufRowBytes)
  205.                 {
  206.                 CopyMem(buf, buffer, nFilled);
  207.                 if (nEmpty > ChunkMoreBytes(cn))    // not enough left to fill buffer
  208.                     {
  209.                     nEmpty = ChunkMoreBytes(cn);
  210.                     bufsize = nFilled + nEmpty;
  211.                     }
  212.                 if (ReadChunkBytes(iff, &buffer[nFilled], nEmpty) < nEmpty)
  213.                     return 1;
  214.  
  215.                 buf = buffer;
  216.                 nFilled = bufsize;
  217.                 }
  218.  
  219.             // copy uncompressed row to destination plane
  220.             if (compression == cmpNone)
  221.                 {
  222.                 if (nFilled < srcRowBytes)
  223.                     return 2;
  224.                 CopyMem(buf, *pDest, srcRowBytes);
  225.                 buf += srcRowBytes;
  226.                 *pDest += destRowBytes;
  227.                 }
  228.             else
  229.                 {  // decompress row to destination plane
  230.                 if (unpackrow(&buf, pDest, nFilled, srcRowBytes))
  231.                     return 2;
  232.                 else
  233.                     *pDest += (destRowBytes - srcRowBytes);
  234.                 }
  235.             }
  236.         }
  237.     return 0;
  238.     }
  239.  
  240. static int loadbody(struct IFFHandle *iff, struct BitMap *bitmap,BitMapHeader *bmhd)
  241.     {
  242.     BYTE *buffer;
  243.     ULONG bufsize;
  244.     LONG err = 0;
  245.     register struct ContextNode *cn = CurrentChunk(iff);
  246.  
  247.     if (!cn)
  248.         return 1;
  249.     if (cn->cn_Type != ID_ILBM || cn->cn_ID != ID_BODY)
  250.         return 1;
  251.     if (bitmap && bmhd)
  252.         {
  253.         bufsize = MaxPackedSize(RowBytes(bmhd->w)) << 4;
  254.         if (!(buffer = AllocMem(bufsize, 0L)))
  255.             return 2;
  256.         err = loadbody2(iff, bitmap, NULL, bmhd, buffer, bufsize);
  257.         }
  258.     FreeMem(buffer, bufsize);
  259.     return err;
  260.     }
  261.  
  262. static void freeIFFHandle(struct IFFHandle *iff)
  263.     {
  264.     CloseIFF(iff);
  265.     if (iff->iff_Stream)
  266.         Close(iff->iff_Stream);
  267.     FreeIFF(iff);
  268.     }
  269.  
  270. static struct IFFHandle *getilbminfo(char *filename, USHORT *wide, USHORT *high, USHORT *deep,
  271.         WORD **colortable, USHORT *colors, unsigned long *mode, BitMapHeader **bmhd)
  272.     {
  273.     struct StoredProperty *sp;
  274.     struct IFFHandle *iff;
  275.  
  276.     if (!IFFParseBase)
  277.         return NULL;
  278.  
  279.     // open things
  280.     if (!(iff = AllocIFF()))
  281.         return NULL;
  282.     if (!(iff->iff_Stream = Open(filename, MODE_OLDFILE)))
  283.         goto iffdone;
  284.     InitIFFasDOS(iff);
  285.     if (OpenIFF(iff, IFFF_READ))
  286.         goto iffdone;
  287.  
  288.     // set up the parser and parse the file
  289.     if (PropChunk(iff, ID_ILBM, ID_BMHD))
  290.         goto iffdone;
  291.     PropChunk(iff, ID_ILBM, ID_CMAP);
  292.     PropChunk(iff, ID_ILBM, ID_CAMG);
  293.     if (StopChunk(iff, ID_ILBM, ID_BODY))
  294.         goto iffdone; // stop at start of body
  295.     if (ParseIFF(iff, IFFPARSE_SCAN))
  296.         goto iffdone;
  297.  
  298.     // extract header and determine dimensions
  299.     // From modules/getbitmap.c
  300.     if (!(sp = FindProp(iff, ID_ILBM, ID_BMHD)))
  301.         goto iffdone;
  302.     *bmhd = (BitMapHeader *)sp->sp_Data;
  303.  
  304.     *wide = RowBits((*bmhd)->w);
  305.     *high = (*bmhd)->h;
  306.     *deep = (*bmhd)->nPlanes;
  307.  
  308.     if (colors)
  309.         {              // get colormap information
  310.         if (sp = FindProp(iff, ID_ILBM, ID_CMAP))
  311.             {
  312.             register unsigned char *rgb = sp->sp_Data;
  313.             long r, g, b;
  314.             unsigned long ncheck;
  315.             unsigned short i, ncolors = *colors = sp->sp_Size / sizeofColorRegister;
  316.  
  317.             if ((ncheck = 1 << (*bmhd)->nPlanes) > ncolors)
  318.                 ncheck = ncolors;
  319. //ifdef PENDING_LATER_INCLUDES
  320.             if (((struct Library *)GfxBase)->lib_Version >= 39)
  321.                 {
  322.                 Color32 *ct;
  323.                 unsigned short AllShifted = TRUE;
  324.                 unsigned short nc = max(ncolors, 32);
  325.  
  326.                 if (!(*colortable = (short *)GuiMalloc((nc*sizeof(Color32)) + (4*sizeof(short)), MEMF_CLEAR)))
  327.                     goto errctab;
  328.                 ct = (Color32 *)(*colortable + 2);
  329.                 **colortable = nc;
  330.  
  331.                 i = 0;
  332.                 while (ncheck--)
  333.                     {
  334.                     ct[i].r   = r = *rgb++;
  335.                     ct[i].g   = g = *rgb++;
  336.                     ct[i++].b = b = *rgb++;
  337.                     if ((r & 0x0f) || (g & 0x0f) || (b & 0x0f))
  338.                         AllShifted = FALSE;
  339.                     }
  340.                 if (AllShifted && ((*bmhd)->flags & BMHDF_CMAPOK))  // shift if 4-bit
  341.                     for (i = 0; i < ncolors; i++)
  342.                         {
  343.                         ct[i].r |= (ct[i].r >> 4);
  344.                         ct[i].g |= (ct[i].g >> 4);
  345.                         ct[i].b |= (ct[i].b >> 4);
  346.                         }
  347.                 for (i = 0; i < ncolors; i++)
  348.                     {  // scale to 32 bits
  349.                     g = ct[i].r;
  350.                     ct[i].r |= ((g << 24) | (g << 16) | (g << 8));
  351.                     g = ct[i].g;
  352.                     ct[i].g |= ((g << 24) | (g << 16) | (g << 8));
  353.                     g = ct[i].b;
  354.                     ct[i].b |= ((g << 24) | (g << 16) | (g << 8));
  355.                     }
  356.                 }
  357.             else
  358. //endif
  359.             if (*colortable = (short *)calloc(ncolors, sizeof(short)))
  360.                 {
  361.                 short *ct = *colortable;
  362.                 while (ncheck--)
  363.                     {
  364.                     r = (*rgb++ & 0xf0) << 4;
  365.                     g = *rgb++ & 0xf0;
  366.                     b = *rgb++ >> 4;
  367.                     *(ct++) = r | g | b;
  368.                     }
  369.                 }
  370.             else
  371.                 {
  372. errctab:
  373.                 *colortable = NULL;
  374.                 *colors = 0xffff;
  375.                 }
  376.             }
  377.         else
  378.             *colors = 0xffff;
  379.         }
  380.  
  381.     return iff;
  382.  
  383. iffdone:
  384.     if (iff)
  385.         freeIFFHandle(iff);
  386.     return NULL;
  387.     }
  388.  
  389. int FoxPow2(int r)
  390.     {
  391.     return 1 << r;
  392.     }
  393.  
  394. BOOL FOXLIB ScreenColoursFromILBM(REGA0 GuiScreen *sc, REGA1 char *fname)
  395.     {
  396.     // Inspect the ilbm file given in fname and set the screen's colours to those in the ilbm.
  397.  
  398.     int pen;
  399.     BitMapHeader *bmhd;
  400.     unsigned short wide, high, deep, colours = sc->scr->ViewPort.ColorMap->Count; //MAXAMCOLORREG;
  401.     short *colourtable = NULL;
  402.     struct IFFHandle *iff = getilbminfo(fname, &wide, &high, &deep,
  403.             &colourtable, &colours, NULL, &bmhd);
  404.  
  405.     if (!iff)
  406.         return FALSE;
  407.     if ((!(sc->nsc)) || !(sc->scr))
  408.         {
  409.         freeIFFHandle(iff);
  410.         return FALSE;
  411.         }
  412.     if (sc->nsc->Depth < deep)
  413.         { // The supplied screen isn't deep enough for this ilbm.
  414.         SetLastErr("The screen isn't deep enough for this ILBM in function ScreenColoursFromILBM.");
  415.         freeIFFHandle(iff);
  416.         return FALSE;
  417.         }
  418.  
  419.     if (colourtable)
  420.         if (((struct Library *)GfxBase)->lib_Version < 39)
  421.             LoadRGB4(&sc->scr->ViewPort, (unsigned short *) colourtable, colours);
  422.         else
  423.             LoadRGB32(&sc->scr->ViewPort, (unsigned long *) colourtable);
  424.  
  425.     if (colourtable)
  426.         GuiFree(colourtable);
  427.     freeIFFHandle(iff);
  428.     // Black is usually in pen 0, white is usually in the last pen.
  429.     pen = FoxPow2(sc->nsc->Depth);
  430.     SetGuiPens(pen - 1, 0);
  431.     return TRUE;
  432.     }
  433.  
  434. static struct BitMap *loadilbmBitMap(char *filename, unsigned short *wide, unsigned short *high,
  435.         unsigned short *deep)
  436.     {
  437.     BitMapHeader *bmhd;
  438.     struct BitMap *bitmap;
  439.     struct IFFHandle *iff = getilbminfo(filename, wide, high, deep, NULL, NULL, NULL, &bmhd);
  440.  
  441.     if (!iff)
  442.         return NULL;
  443.  
  444.     // Allocate a bitmap according to the data in the bitmap header and load the ILBM file into the bitmap
  445.     if (bitmap = getBitMap(*wide, *high, *deep, 1))
  446.         if (loadbody(iff, bitmap, bmhd))
  447.             {
  448.             freeBitMap(bitmap);    // Load was unsuccessful
  449.             bitmap = NULL;
  450.             }
  451.     freeIFFHandle(iff);    // IFF handle must be freed before exiting
  452.     return bitmap;
  453.     }
  454.  
  455. BOOL FOXLIB HideBitMap(REGA0 BitMapInstance *bmi)
  456.     {
  457.     if (!bmi)
  458.         return FALSE;
  459.     
  460.     AreaBlank(bmi->win->Win->RPort, bmi->left, bmi->top, bmi->bm->width, bmi->bm->height);
  461.     GuiFree(bmi);
  462.     return TRUE;
  463.     }
  464.  
  465. BitMapInstance* FOXLIB ShowBitMap(REGA0 GuiBitMap *bm, REGA1 GuiWindow *w, REGD0 unsigned short x, REGD1 unsigned short y,
  466.         REGD2 short flags)
  467.     {
  468.     if (bm && w)
  469.         {
  470.         BitMapInstance *bmi = (BitMapInstance *) GuiMalloc(sizeof(BitMapInstance), 0);
  471.  
  472.         if (!bmi)
  473.             return NULL;
  474.         bmi->win = w;
  475.         bmi->left = x;
  476.         bmi->top = y;
  477.         bmi->bm = bm;
  478.         BltBitMapRastPort(bm->bm, 0L, 0L, w->Win->RPort, (long) x, (long) y, (long) (bm->width),
  479.                 (long) (bm->height), (flags & BM_OVERLAY ? 0x60 : 0xC0));
  480.         WaitBlit();
  481.         return bmi;
  482.         }
  483.     return NULL;
  484.     }
  485.  
  486. GuiBitMap* FOXLIB LoadBitMap(REGA0 char *fname)
  487.     {
  488.     unsigned short wide, high, deep;
  489.     GuiBitMap *gbm;
  490.  
  491.     if (!fname)
  492.         return NULL;
  493.  
  494.     if (!IFFParseBase)
  495.         return NULL;
  496.  
  497.     if (!(gbm = (GuiBitMap *) GuiMalloc(sizeof(GuiBitMap), 0)))
  498.         return NULL;
  499.  
  500.     if (!(gbm->bm = loadilbmBitMap(fname, &wide, &high, &deep)))
  501.         {
  502.         GuiFree(gbm);
  503.         return NULL;
  504.         }
  505.     gbm->width = wide;
  506.     gbm->height = high;
  507.     gbm->depth = deep;
  508.     gbm->flags = 0;
  509.     gbm->bmi = NULL;
  510.     gbm->next = gbm->obm = NULL;
  511.  
  512.     return gbm;
  513.     }
  514.  
  515. BOOL FOXLIB FreeGuiBitMap(REGA0 GuiBitMap *bm)
  516.     {
  517.     if (bm)
  518.         {
  519.         freeBitMap(bm->bm);
  520.         GuiFree(bm);
  521.         return TRUE;
  522.         }
  523.     return FALSE;
  524.     }
  525.  
  526. BOOL FOXLIB RedrawBitMap(REGA0 BitMapInstance *bmi)
  527.     {
  528.     if (bmi)
  529.         {
  530. /*        struct GuiWindow *win = bmi->win;
  531.         GuiBitMap *bm = bmi->bm;
  532.         unsigned short left = bmi->left, top = bmi->top;
  533.  
  534.         HideBitMap(bmi);
  535.         ShowBitMap(bm, win, left, top, bm->flags);
  536. */
  537.         BltBitMapRastPort(bmi->bm->bm, 0L, 0L, bmi->win->Win->RPort, (long) bmi->left, (long) bmi->top,
  538.                 (long) (bmi->bm->width), (long) (bmi->bm->height), (bmi->bm->flags & BM_OVERLAY ? 0x60 : 0xC0));
  539.         WaitBlit();
  540.  
  541.         return TRUE;
  542.         }
  543.     return FALSE;
  544.     }
  545.  
  546. static GuiBitMap *GetBitMap(unsigned short width, unsigned short height, unsigned short depth, short clear)
  547.     {
  548.     GuiBitMap *gbm;
  549.  
  550.     if (!(gbm = (GuiBitMap *) GuiMalloc(sizeof(GuiBitMap), 0)))
  551.         return NULL;
  552.  
  553.     if (!(gbm->bm = getBitMap(width, height, depth, clear)))
  554.         {
  555.         GuiFree(gbm);
  556.         return NULL;
  557.         }
  558.     gbm->width = width;
  559.     gbm->height = height;
  560.     gbm->depth = depth;
  561.     gbm->flags = 0;
  562.     gbm->bmi = NULL;
  563.     gbm->next = gbm->obm = NULL;
  564.     return gbm;
  565.     }
  566.  
  567. GuiBitMap* FOXLIB ScaleBitMap(REGA0 GuiBitMap *source, REGD0 unsigned short destwidth, REGD1 unsigned short destheight)
  568.     {
  569.     GuiBitMap *destgbm;
  570.     struct BitScaleArgs bsa;
  571.  
  572.     if (!(source && destwidth > 0 && destheight > 0 && Gui.LibVersion >= 36))
  573.         return NULL;
  574.     if (!(destgbm = GetBitMap(destwidth, destheight, source->depth, TRUE)))
  575.         return NULL;
  576.  
  577.     memset(&bsa, 0, sizeof(struct BitScaleArgs));
  578.     bsa.bsa_SrcWidth = source->width;
  579.     bsa.bsa_SrcHeight = source->height;
  580.     bsa.bsa_XSrcFactor = source->width;
  581.     bsa.bsa_XDestFactor = destwidth;
  582.     bsa.bsa_YSrcFactor = source->height;
  583.     bsa.bsa_YDestFactor = destheight;
  584.     bsa.bsa_SrcBitMap = source->bm;
  585.     bsa.bsa_DestBitMap = destgbm->bm;
  586.  
  587.     while (bsa.bsa_XSrcFactor > 16383 || bsa.bsa_XDestFactor > 16383)
  588.         {
  589.         bsa.bsa_XSrcFactor /= 2;
  590.         bsa.bsa_XDestFactor /= 2;
  591.         }
  592.     while (bsa.bsa_YSrcFactor > 16383 || bsa.bsa_YDestFactor > 16383)
  593.         {
  594.         bsa.bsa_YSrcFactor /= 2;
  595.         bsa.bsa_YDestFactor /= 2;
  596.         }
  597.  
  598.     BitMapScale(&bsa);
  599.     WaitBlit(); // Wait for our blit(s) to finish incase the user wants to immediately free the source bm.
  600.  
  601.     destgbm->width = destwidth;
  602.     destgbm->height = destheight;
  603.     destgbm->depth = source->depth;
  604.     destgbm->bmi = source->bmi;
  605.     destgbm->flags = source->flags;
  606.     destgbm->next = destgbm->obm = NULL;
  607.  
  608.     return destgbm;
  609.     }
  610.  
  611.  
  612. /*    Attach a bitmap (or a portion of a bitmap) to a control.  left, top are the offsets of the first
  613.     pixel of the bitmap to use and width, height are the extent of the bitmap to use.  Set width and
  614.     height to -1 to use the remainder of the bitmap. */
  615. BOOL FOXLIB AttachBitMapToControl(REGA0 GuiBitMap *gbm, REGA1 void *control, REGD0 short left, REGD1 short top, REGD2 short width,
  616.         REGD3 short height, REGD4 int flags)
  617.     {
  618.     PushButton *pb = (PushButton *) control;
  619.     GuiBitMap *ngbm, *clip, *list;
  620.     int ObjectWidth = pb->button.Width, ObjectHeight = pb->button.Height;
  621.  
  622.     if (!(gbm && control))
  623.         return FALSE;
  624.  
  625.     // control may be a Frame or a PushButton.  The first three elements of each are identical.
  626.     if (!(pb->WidgetData->ObjectType == FrameObject || pb->WidgetData->ObjectType == ButtonObject))
  627.         return FALSE;
  628.  
  629.     if (pb->WidgetData->ObjectType == FrameObject)
  630.     {
  631.         Frame *fm = (Frame *) control;
  632.         ObjectWidth = fm->points[8] + 1;
  633.         ObjectHeight = fm->points[1] + 1;
  634.     }
  635.  
  636.     if (ObjectWidth < 3 || ObjectHeight < 3)
  637.         return FALSE;
  638.  
  639.     if (width == -1)
  640.         width = gbm->width - left;
  641.     if (height == -1)
  642.         height = gbm->height - top;
  643.  
  644.     if (width < 1 || height < 1)
  645.         return FALSE;
  646.  
  647.     if (left == 0 && top == 0 && width == gbm->width && height == gbm->height)
  648.         // The user wants to use the whole bitmap supplied so no need to clip it.
  649.         clip = NULL;
  650.     else
  651.         {
  652.         // First cut out the portion of the bitmap we want to use and create a new bitmap out of it.
  653.         if (!(clip = GetBitMap(width, height, gbm->depth, TRUE)))
  654.             return FALSE;
  655.         if (!BltBitMap(gbm->bm, left, top, clip->bm, 0, 0, width, height, 0xC0, 0xFF, NULL))
  656.             {
  657.             FreeGuiBitMap(clip);
  658.             return FALSE;
  659.             }
  660.         }
  661.  
  662.     // Bit map scaling is not supported prior to V36 so assume BM_CLIP for V35 and below.
  663.     if ((flags & BM_SCALE) && Gui.LibVersion >= 36)
  664.         ngbm = ScaleBitMap(clip ? clip : gbm, ObjectWidth - 2, ObjectHeight - 2);
  665.     else // BM_CLIP
  666.         {
  667.         if (!(ngbm = GetBitMap(ObjectWidth - 2, ObjectHeight - 2, gbm->depth, TRUE)))
  668.             {
  669.             if (clip)
  670.                 FreeGuiBitMap(clip);
  671.             return FALSE;
  672.             }
  673.         if (!(BltBitMap((clip ? clip : gbm)->bm, 0, 0, ngbm->bm, 0, 0, ObjectWidth - 2, ObjectHeight - 2, 0xC0, 0xFF, NULL)))
  674.             {
  675.             if (clip)
  676.                 FreeGuiBitMap(clip);
  677.             FreeGuiBitMap(ngbm);
  678.             return FALSE;
  679.             }
  680.         WaitBlit(); // Wait for our blit(s) to finish before continuing.
  681.         }
  682.  
  683.     ngbm->flags = flags;
  684.     if (clip)
  685.         FreeGuiBitMap(clip);
  686.  
  687.     /* If the BM_SMART flag is specified and the control is autosizing then keep a copy of the original
  688.         bitmap so that when the window is resized we can redraw the buttons bitmap(s) by reference to the
  689.         original and the bitmap won't lose any definition.  If the BM_SMART flag is not specified
  690.         (BM_STUPID) then resizing the button will reference the bitmap currently on the button and will
  691.         just scale that.  Multiple resizes will then cause loss of definition but the images will use
  692.         less memory. */
  693.     if (pb->WidgetData->flags & S_AUTO_SIZE && (flags & BM_SMART))
  694.         {
  695.         /*    We need a copy of the original GuiBitMap so that we can resize/clip the bitmap if the
  696.             button/frame is resized. */
  697.         if (!(ngbm->obm = GetBitMap(clip ? clip->width : gbm->width - left, clip ? clip->height : gbm->height - top, gbm->depth, FALSE)))
  698.             {
  699.             FreeGuiBitMap(ngbm);
  700.             return FALSE;
  701.             }
  702.         ngbm->obm->flags = flags;
  703.         if (!BltBitMap(gbm->bm, left, top, ngbm->obm->bm, 0, 0, clip ? clip->width : gbm->width - left, clip ? clip->height : gbm->height - top, 0xC0, 0xFF, NULL))
  704.             { // We couldn't copy the bitmap.
  705.             FreeGuiBitMap(ngbm->obm);
  706.             FreeGuiBitMap(ngbm);
  707.             return FALSE;
  708.             }
  709.         }
  710.     else
  711.         ngbm->obm = NULL;
  712.  
  713.     // Draw the bitmap on the button
  714.     if (GadInWinList(&pb->button, ((GuiWindow *) pb->button.UserData)->Win))
  715.         ngbm->bmi = ShowBitMap(ngbm, (GuiWindow *) pb->button.UserData, pb->button.LeftEdge + 1, pb->button.TopEdge + 1, flags);
  716.     else // The button/frame is currently hidden.
  717.         ngbm->bmi = NULL;
  718.  
  719.     /*    Add the bitmap to the buttons list of bitmaps - we MUST add it to the end of the list NOT the
  720.         start because that way when we re-draw the bitmaps, any that are overlaid will be overlaid in the
  721.         correct order. */
  722.     list = pb->bitmap;
  723.     while (list && list->next)
  724.         list = list->next;
  725.     if (list)
  726.         list->next = ngbm;
  727.     else
  728.         pb->bitmap = ngbm;
  729.     return TRUE;
  730.     }
  731.